import [Value,Scope,Symbol,Errors,Function,vList]
import structs/[ArrayList,HashMap]

Macro : class extends Value {
    name : String
    args : ArrayList<Symbol>
    body : Value
    
    init : func ~withoutLine (=name,=args,=body)
    init : func ~withLine (=name,=args,=body,=line)
    
    toString : func -> String { name }
    
    equals? : func(other : Value) -> Bool {
        other class == This && other as Macro name == this name
    }
    
    call : func(arguments : ArrayList<Value>, decorativeScope : Scope) -> Value {
        scope := Scope new()
        if(arguments size != args size) { //Make sure the correct amount of parameters passed to the macro
            ArgumentsNotEqualToError new(name,args size,arguments size,line) throw()
        }
    
        toCall := body clone()
    
        for(i in 0 .. arguments size) {
            // replace all occurences of args[i] by arguments[i] in the body and then execute it in decorativeScope 
            if(toCall class == vList) {
                toCall as vList replaceAll(args[i] as Value,arguments[i])
            } else if(toCall equals?(args[i])) {
                toCall = arguments[i]
            }
        }
        
        toCall evaluate(decorativeScope) evaluate(decorativeScope) // We use a double evaluate because a list returned by a macro is then supposed to be
                                                                    // evaluated
    }
}